﻿using Ellanet.Annotations;
using Ellanet.Classes;
using Ellanet.Utilities;
using Ellanet.Wrappers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Media;
using System.Runtime.CompilerServices;
using System.Threading;
using Timer = System.Timers.Timer;

namespace Ellanet.ViewModels
{
    public class PractiseWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public event RequestViewCloseHandler RequestViewClose;

        private Sum _sum;
        private List<Choice> _choices;
        private readonly List<Sum> _sums;
        private DateTime _sumStartTime = DateTime.Now;
        private readonly Timer _intervalTimer;
        private bool _isSumAwaitingAnswer;
        //private readonly SpeechRecognizer _recogniser = new SpeechRecognizer();

        public delegate void RequestViewCloseHandler();

        public Sum Sum
        {
            get { return _sum; }
            set
            {
                _sum = value;
                OnPropertyChanged();
            }
        }

        public List<Choice> Choices
        {
            get { return _choices; }
            set
            {
                _choices = value;
                OnPropertyChanged();
            }
        }

        public RelayCommand AnswerCommand { get; set; }

        public TimeSpan TotalTime { get; set; }

        public TimeSpan FastestAnswerTime { get; set; } = TimeSpan.MaxValue;

        public TimeSpan SlowestAnswerTime { get; set; } = TimeSpan.MinValue;

        public Sum FastestAnswer { get; set; }

        public Sum SlowestAnswer { get; set; }

        public TimeSpan SumTime => DateTime.Now.Subtract(_sumStartTime);

        public int CorrectAnswers { get; private set; }

        public int IncorrectAnswers { get; private set; }

        public TimeSpan Interval { get; }

        public bool IsSumAwaitingAnswer
        {
            get { return _isSumAwaitingAnswer; }
            set
            {
                _isSumAwaitingAnswer = value;
                OnPropertyChanged();
            }
        }

        //public TimeSpan SumTime => _sumStartTime.Add(_interval).Subtract( DateTime.Now);

        public PractiseWindowViewModel(List<Sum> sums, TimeSpan interval)
        {
            AnswerCommand = new RelayCommand(Answer);
            Interval = interval;
            _sums = sums;
            _intervalTimer = new Timer
            {
                Interval = 100
            };
            _intervalTimer.Elapsed += _intervalTimer_Elapsed;
            //_recogniser.SpeechRecognized += _recogniser_SpeechRecognized;
            ThreadPool.QueueUserWorkItem(AdvanceToNextSum);
        }

        //private void _recogniser_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        //{
        //    Debug.WriteLine("Speech recognised: " + e.Result.Text);
        //    Answer(new Choice(Convert.ToInt32(e.Result.Text), false));
        //}

        private void _intervalTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            OnPropertyChanged(nameof(SumTime));
        }

        public void Answer(object param)
        {
            var sumTime = SumTime;
            TotalTime += sumTime;
            _intervalTimer.Stop();

            //todo Only when correct (if so, test if none correct)?
            if (sumTime < FastestAnswerTime)
            {
                FastestAnswerTime = sumTime;
                FastestAnswer = Sum;
            }

            if (sumTime > SlowestAnswerTime)
            {
                SlowestAnswerTime = sumTime;
                SlowestAnswer = Sum;
            }

            var paramChoice = (Choice) param;
            Debug.WriteLine(paramChoice.IsCorrect);

            if (!Choices.Any(c => c.IsChosen))
            {
                var choice = Choices.First(c => c.Answer.Equals(paramChoice.Answer));

                if (choice != null)
                {
                    choice.IsChosen = true;
                    var player = new SoundPlayer();

                    if (choice.IsCorrect)
                    {
                        CorrectAnswers++;
                        player.Stream = Properties.Resources.Correct;
                    }
                    else
                    {
                        IncorrectAnswers++;
                        player.Stream = Properties.Resources.Incorrect;
                    }

                    player.Play();
                }

                ThreadPool.QueueUserWorkItem(PauseBetweenSums);
            }
        }

        private void PauseBetweenSums(object stateInfo)
        {
            Thread.Sleep(2000);
            IsSumAwaitingAnswer = false;
            ThreadPool.QueueUserWorkItem(AdvanceToNextSum);
        }

        private void AdvanceToNextSum(object stateInfo)
        {
            Choices = null;

            if (Sum == null)
            {
                Sum = _sums.First();
            }
            else if (Sum.Equals(_sums.Last()))
            {
                OnRequestViewClose();
                return;
            }
            else
            {
                Sum = _sums.Skip(_sums.IndexOf(Sum) + 1).First();
            }

            SpeechWrapper.Say(String.Format("{0} times {1}", Sum.Multiplicand, Sum.Multiplier), true);
            var choices = new List<Choice>(new[] {new Choice(Sum.Answer, true)});

            while (choices.Count < 4)
            {
                int upper = ((Sum.Multiplicand + 1)*Sum.Multiplier) + 1;
                int lower = ((Sum.Multiplicand - 1)*Sum.Multiplier).Equals(0) ? 1 : ((Sum.Multiplicand - 1)*Sum.Multiplier);
                int randomAnswer = new Random().Next(lower, upper);

                if (!choices.Any(choice => choice.Answer.Equals(randomAnswer)))
                {
                    choices.Add(new Choice(randomAnswer, false));
                }
            }

            //_recogniser.UnloadAllGrammars();
            //_recogniser.LoadGrammar(new Grammar(new GrammarBuilder(new Choices((from Choice c in choices select c.Answer.ToString()).ToArray()))));
            Choices = choices.OrderBy(choice => Guid.NewGuid()).ToList();
            _sumStartTime = DateTime.Now;
            _intervalTimer.Start();
            IsSumAwaitingAnswer = true;
        }

        protected void OnRequestViewClose()
        {
            RequestViewClose?.Invoke();
        }

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
